package com.nutrition.health.service.impl;

import com.nutrition.health.model.DietRecord;
import com.nutrition.health.model.DietRecord.MealType;
import com.nutrition.health.model.FoodItem;
import com.nutrition.health.model.NutritionInfo;
import com.nutrition.health.model.User;
import com.nutrition.health.repository.DietRecordRepository;
import com.nutrition.health.repository.FoodItemRepository;
import com.nutrition.health.repository.UserRepository;
import com.nutrition.health.service.DietRecordService;
import com.nutrition.health.service.UserHealthProfileService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;

import javax.transaction.Transactional;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.*;
import java.util.stream.Collectors;

@Service
@Transactional
public class DietRecordServiceImpl implements DietRecordService {

    private final DietRecordRepository dietRecordRepository;
    private final UserRepository userRepository;
    private final FoodItemRepository foodItemRepository;
    private final UserHealthProfileService userHealthProfileService;

    @Autowired
    public DietRecordServiceImpl(
            DietRecordRepository dietRecordRepository,
            UserRepository userRepository,
            FoodItemRepository foodItemRepository,
            UserHealthProfileService userHealthProfileService) {
        this.dietRecordRepository = dietRecordRepository;
        this.userRepository = userRepository;
        this.foodItemRepository = foodItemRepository;
        this.userHealthProfileService = userHealthProfileService;
    }

    @Override
    public List<DietRecord> getAllDietRecordsByUserId(Long userId) {
        User user = userRepository.findById(userId)
                .orElseThrow(() -> new RuntimeException("User not found with id: " + userId));
        
        return dietRecordRepository.findByUser(user);
    }

    @Override
    public Page<DietRecord> getAllDietRecordsByUserId(Long userId, Pageable pageable) {
        User user = userRepository.findById(userId)
                .orElseThrow(() -> new RuntimeException("User not found with id: " + userId));
        
        return dietRecordRepository.findByUser(user, pageable);
    }

    @Override
    public Optional<DietRecord> getDietRecordById(Long id) {
        return dietRecordRepository.findById(id);
    }

    @Override
    public List<DietRecord> getDietRecordsByUserIdAndMealType(Long userId, MealType mealType) {
        User user = userRepository.findById(userId)
                .orElseThrow(() -> new RuntimeException("User not found with id: " + userId));
        
        return dietRecordRepository.findByUserAndMealType(user, mealType);
    }

    @Override
    public List<DietRecord> getDietRecordsByUserIdAndDateRange(Long userId, LocalDate startDate, LocalDate endDate) {
        User user = userRepository.findById(userId)
                .orElseThrow(() -> new RuntimeException("User not found with id: " + userId));
        
        LocalDateTime startDateTime = startDate.atStartOfDay();
        LocalDateTime endDateTime = endDate.atTime(LocalTime.MAX);
        
        return dietRecordRepository.findByUserAndConsumptionTimeBetween(user, startDateTime, endDateTime);
    }

    @Override
    public DietRecord createDietRecord(Long userId, DietRecord dietRecord) {
        User user = userRepository.findById(userId)
                .orElseThrow(() -> new RuntimeException("User not found with id: " + userId));
        
        dietRecord.setUser(user);
        return dietRecordRepository.save(dietRecord);
    }

    @Override
    public DietRecord updateDietRecord(Long id, DietRecord dietRecordDetails) {
        DietRecord dietRecord = dietRecordRepository.findById(id)
                .orElseThrow(() -> new RuntimeException("Diet record not found with id: " + id));
        
        dietRecord.setConsumptionTime(dietRecordDetails.getConsumptionTime());
        dietRecord.setMealType(dietRecordDetails.getMealType());
        dietRecord.setNotes(dietRecordDetails.getNotes());
        
        // 不直接更新食品列表，应该通过专门的方法添加或移除食品
        
        return dietRecordRepository.save(dietRecord);
    }

    @Override
    public void deleteDietRecord(Long id) {
        dietRecordRepository.deleteById(id);
    }

    @Override
    public DietRecord addFoodItemToDietRecord(Long dietRecordId, Long foodItemId) {
        DietRecord dietRecord = dietRecordRepository.findById(dietRecordId)
                .orElseThrow(() -> new RuntimeException("Diet record not found with id: " + dietRecordId));
        
        FoodItem foodItem = foodItemRepository.findById(foodItemId)
                .orElseThrow(() -> new RuntimeException("Food item not found with id: " + foodItemId));
        
        dietRecord.getFoodItems().add(foodItem);
        return dietRecordRepository.save(dietRecord);
    }

    @Override
    public DietRecord removeFoodItemFromDietRecord(Long dietRecordId, Long foodItemId) {
        DietRecord dietRecord = dietRecordRepository.findById(dietRecordId)
                .orElseThrow(() -> new RuntimeException("Diet record not found with id: " + dietRecordId));
        
        FoodItem foodItem = foodItemRepository.findById(foodItemId)
                .orElseThrow(() -> new RuntimeException("Food item not found with id: " + foodItemId));
        
        dietRecord.getFoodItems().remove(foodItem);
        return dietRecordRepository.save(dietRecord);
    }

    @Override
    public double calculateTotalCaloriesForUserInDateRange(Long userId, LocalDate startDate, LocalDate endDate) {
        User user = userRepository.findById(userId)
                .orElseThrow(() -> new RuntimeException("User not found with id: " + userId));
        
        LocalDateTime startDateTime = startDate.atStartOfDay();
        LocalDateTime endDateTime = endDate.atTime(LocalTime.MAX);
        
        Double totalCalories = dietRecordRepository.calculateTotalCaloriesForUserInTimeRange(
                user, startDateTime, endDateTime);
        
        return totalCalories != null ? totalCalories : 0.0;
    }

    @Override
    public Map<String, Double> calculateNutrientIntakeForUserInDateRange(Long userId, LocalDate startDate, LocalDate endDate) {
        User user = userRepository.findById(userId)
                .orElseThrow(() -> new RuntimeException("User not found with id: " + userId));
        
        LocalDateTime startDateTime = startDate.atStartOfDay();
        LocalDateTime endDateTime = endDate.atTime(LocalTime.MAX);
        
        List<DietRecord> dietRecords = dietRecordRepository.findByUserAndConsumptionTimeBetween(
                user, startDateTime, endDateTime);
        
        // 初始化营养素摄入映射
        Map<String, Double> nutrientIntake = new HashMap<>();
        nutrientIntake.put("calories", 0.0);
        nutrientIntake.put("protein", 0.0);
        nutrientIntake.put("carbohydrates", 0.0);
        nutrientIntake.put("fat", 0.0);
        nutrientIntake.put("fiber", 0.0);
        nutrientIntake.put("sugar", 0.0);
        nutrientIntake.put("sodium", 0.0);
        nutrientIntake.put("cholesterol", 0.0);
        
        // 计算总营养素摄入
        for (DietRecord record : dietRecords) {
            for (FoodItem foodItem : record.getFoodItems()) {
                NutritionInfo nutritionInfo = foodItem.getNutritionInfo();
                if (nutritionInfo != null) {
                    nutrientIntake.put("calories", nutrientIntake.get("calories") + nutritionInfo.getCalories());
                    
                    if (nutritionInfo.getProtein() != null) {
                        nutrientIntake.put("protein", nutrientIntake.get("protein") + nutritionInfo.getProtein());
                    }
                    
                    if (nutritionInfo.getCarbohydrates() != null) {
                        nutrientIntake.put("carbohydrates", nutrientIntake.get("carbohydrates") + nutritionInfo.getCarbohydrates());
                    }
                    
                    if (nutritionInfo.getFat() != null) {
                        nutrientIntake.put("fat", nutrientIntake.get("fat") + nutritionInfo.getFat());
                    }
                    
                    if (nutritionInfo.getFiber() != null) {
                        nutrientIntake.put("fiber", nutrientIntake.get("fiber") + nutritionInfo.getFiber());
                    }
                    
                    if (nutritionInfo.getSugar() != null) {
                        nutrientIntake.put("sugar", nutrientIntake.get("sugar") + nutritionInfo.getSugar());
                    }
                    
                    if (nutritionInfo.getSodium() != null) {
                        nutrientIntake.put("sodium", nutrientIntake.get("sodium") + nutritionInfo.getSodium());
                    }
                    
                    if (nutritionInfo.getCholesterol() != null) {
                        nutrientIntake.put("cholesterol", nutrientIntake.get("cholesterol") + nutritionInfo.getCholesterol());
                    }
                }
            }
        }
        
        return nutrientIntake;
    }

    @Override
    public Map<String, Object> analyzeDietaryPatterns(Long userId, LocalDate startDate, LocalDate endDate) {
        User user = userRepository.findById(userId)
                .orElseThrow(() -> new RuntimeException("User not found with id: " + userId));
        
        LocalDateTime startDateTime = startDate.atStartOfDay();
        LocalDateTime endDateTime = endDate.atTime(LocalTime.MAX);
        
        List<DietRecord> dietRecords = dietRecordRepository.findByUserAndConsumptionTimeBetween(
                user, startDateTime, endDateTime);
        
        Map<String, Object> analysis = new HashMap<>();
        
        // 分析餐食类型分布
        Map<MealType, Long> mealTypeDistribution = dietRecords.stream()
                .collect(Collectors.groupingBy(DietRecord::getMealType, Collectors.counting()));
        analysis.put("mealTypeDistribution", mealTypeDistribution);
        
        // 分析食品类别分布
        Map<FoodItem.FoodCategory, Long> foodCategoryDistribution = new HashMap<>();
        for (DietRecord record : dietRecords) {
            for (FoodItem foodItem : record.getFoodItems()) {
                FoodItem.FoodCategory category = foodItem.getCategory();
                foodCategoryDistribution.put(category, foodCategoryDistribution.getOrDefault(category, 0L) + 1);
            }
        }
        analysis.put("foodCategoryDistribution", foodCategoryDistribution);
        
        // 分析每日卡路里摄入趋势
        Map<LocalDate, Double> dailyCalorieIntake = new HashMap<>();
        for (LocalDate date = startDate; !date.isAfter(endDate); date = date.plusDays(1)) {
            double calories = calculateTotalCaloriesForUserInDateRange(userId, date, date);
            dailyCalorieIntake.put(date, calories);
        }
        analysis.put("dailyCalorieIntake", dailyCalorieIntake);
        
        // 分析常见食品
        Map<String, Long> commonFoods = dietRecords.stream()
                .flatMap(record -> record.getFoodItems().stream())
                .collect(Collectors.groupingBy(FoodItem::getName, Collectors.counting()));
        
        // 获取前10个最常见的食品
        List<Map.Entry<String, Long>> topFoods = commonFoods.entrySet().stream()
                .sorted(Map.Entry.<String, Long>comparingByValue().reversed())
                .limit(10)
                .collect(Collectors.toList());
        
        analysis.put("commonFoods", topFoods);
        
        return analysis;
    }

    @Override
    public Map<String, Object> compareActualVsRecommendedIntake(Long userId, LocalDate date) {
        // 获取用户的推荐营养摄入
        Map<String, Double> recommendedIntake = userHealthProfileService.generateNutrientRequirements(userId);
        
        // 获取用户的实际营养摄入
        Map<String, Double> actualIntake = calculateNutrientIntakeForUserInDateRange(userId, date, date);
        
        // 比较实际摄入与推荐摄入
        Map<String, Object> comparison = new HashMap<>();
        comparison.put("recommended", recommendedIntake);
        comparison.put("actual", actualIntake);
        
        // 计算差异百分比
        Map<String, Double> differencePercentage = new HashMap<>();
        for (String nutrient : recommendedIntake.keySet()) {
            if (actualIntake.containsKey(nutrient) && recommendedIntake.get(nutrient) > 0) {
                double diff = (actualIntake.get(nutrient) / recommendedIntake.get(nutrient)) * 100 - 100;
                differencePercentage.put(nutrient, diff);
            }
        }
        comparison.put("differencePercentage", differencePercentage);
        
        // 生成建议
        List<String> suggestions = new ArrayList<>();
        
        // 卡路里建议
        if (differencePercentage.containsKey("calories")) {
            double calorieDiff = differencePercentage.get("calories");
            if (calorieDiff < -10) {
                suggestions.add("您的卡路里摄入低于推荐值，可以适当增加食物摄入量。");
            } else if (calorieDiff > 10) {
                suggestions.add("您的卡路里摄入高于推荐值，建议控制食物摄入量。");
            } else {
                suggestions.add("您的卡路里摄入在推荐范围内，继续保持！");
            }
        }
        
        // 蛋白质建议
        if (differencePercentage.containsKey("protein")) {
            double proteinDiff = differencePercentage.get("protein");
            if (proteinDiff < -10) {
                suggestions.add("您的蛋白质摄入不足，建议增加瘦肉、鱼、蛋、豆类等富含蛋白质的食物。");
            } else if (proteinDiff > 30) {
                suggestions.add("您的蛋白质摄入过高，建议适当减少，并确保摄入多样化的食物。");
            }
        }
        
        // 碳水化合物建议
        if (differencePercentage.containsKey("carbohydrates")) {
            double carbsDiff = differencePercentage.get("carbohydrates");
            if (carbsDiff < -10) {
                suggestions.add("您的碳水化合物摄入不足，建议增加全谷物、水果等食物。");
            } else if (carbsDiff > 20) {
                suggestions.add("您的碳水化合物摄入过高，建议减少精制碳水化合物的摄入，如白面包、糖果等。");
            }
        }
        
        // 脂肪建议
        if (differencePercentage.containsKey("fat")) {
            double fatDiff = differencePercentage.get("fat");
            if (fatDiff < -10) {
                suggestions.add("您的脂肪摄入不足，建议适当增加健康脂肪的摄入，如橄榄油、坚果等。");
            } else if (fatDiff > 20) {
                suggestions.add("您的脂肪摄入过高，建议减少油炸食品和高脂肪食物的摄入。");
            }
        }
        
        // 纤维建议
        if (differencePercentage.containsKey("fiber")) {
            double fiberDiff = differencePercentage.get("fiber");
            if (fiberDiff < -20) {
                suggestions.add("您的膳食纤维摄入不足，建议增加蔬菜、水果、全谷物和豆类的摄入。");
            }
        }
        
        comparison.put("suggestions", suggestions);
        
        return comparison;
    }
}